package com.example.lotterysystem.service.mq;
import cn.hutool.core.date.DateUtil;
import com.example.lotterysystem.common.config.ExecutorConfig;
import com.example.lotterysystem.common.exception.ServiceException;
import com.example.lotterysystem.common.utils.JacksonUtil;

import com.example.lotterysystem.common.utils.MailUtil;
import com.example.lotterysystem.controller.param.DrawPrizeParam;
import com.example.lotterysystem.controller.param.MessageWrapper;
import com.example.lotterysystem.dao.dataobject.ActivityPrizeDO;
import com.example.lotterysystem.dao.dataobject.WinningRecordDO;
import com.example.lotterysystem.dao.mapper.ActivityPrizeMapper;
import com.example.lotterysystem.dao.mapper.WinningRecordMapper;
import com.example.lotterysystem.service.DrawPrizeService;
import com.example.lotterysystem.service.activitystatus.ActivityStatusManager;
import com.example.lotterysystem.service.dto.ConvertActivityStatusDTO;
import com.example.lotterysystem.service.enums.ActivityPrizeStatusEnum;
import com.example.lotterysystem.service.enums.ActivityPrizeTiersEnum;
import com.example.lotterysystem.service.enums.ActivityStatusEnum;
import com.example.lotterysystem.service.enums.ActivityUserStatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.annotation.RabbitListeners;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.example.lotterysystem.common.config.DirectRabbitConfig.QUEUE_NAME;

@Slf4j
@Component
@Service
@EnableRabbit
public class MqReceiver {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private DrawPrizeService drawPrizeService;
    @Autowired
    private ActivityStatusManager activityStatusManager;
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Autowired
    private ActivityPrizeMapper activityPrizeMapper;
    @Autowired
    private WinningRecordMapper winningRecordMapper;
    @Autowired
    private MailUtil mailUtil;
//
//    @RabbitListener(queues = QUEUE_NAME)
//    public void process(MessageWrapper wrapper) {
//        try {
////            log.info("MQ成功接收到消息,message:{}", messageJson);
////            Map<String, String> message = JacksonUtil.readValue(messageJson, Map.class);
////            String paramStr = message.get("messageData");
////            DrawPrizeParam param = JacksonUtil.readValue(paramStr, DrawPrizeParam.class);
//            log.info("MQ接收到消息: {}", JacksonUtil.writeValueAsString(wrapper));
//            DrawPrizeParam param = wrapper.getMessageData();
//            log.info("抽奖参数已解析: {}", param);
//            // 继续处理...
//        } catch (Exception e) {
//            log.error("处理消息时出现异常", e);
//        }
//    }


    @RabbitListener(queues = QUEUE_NAME)
    public void process(Map<String, String> message) {

            log.info("MQ成功接收到消息,message:{}", message);

            // 直接从 Map 中取 JSON 字符串并解析
            String paramStr = message.get("messageData");
            DrawPrizeParam param = JacksonUtil.readValue(paramStr, DrawPrizeParam.class);

            log.info("抽奖参数解析成功: {}", param);
            // 后续业务处理逻辑
            //处理抽奖流程

            try {
//                if (true){
//                   return;
//                }
                //校验抽奖请求是否有效
                drawPrizeService.checkDrawPrize(param);
                //状态扭转!!!!!!!
                statusConvert(param);

                //保存中奖者名单
                List<WinningRecordDO>  winnerRecordDOList=drawPrizeService.saveWinnerRecords(param);

                //通知中奖者
                syncExecute(winnerRecordDOList);
            }catch (ServiceException e){
                log.error("处理MQ消息异常！{}：{}",e.getCode(),e.getMessage(),e);
                rollback(param);
                throw e;
            }catch (Exception e){
                log.error("处理MQ消息异常！:{}",e);
                rollback(param);
                throw e;
            }

            //如果异常，需要保证事物一致性（回滚），抛出异常

    }

    /**
     * 处理抽奖异常回滚行为
     * @param param
     */
    private void rollback(DrawPrizeParam param) {
        //1、回滚状态：活动、奖品、人品
        //状态是否需要回滚
        if (!statusNeedRollback(param)){
            //不需要：return
            return;
        }
        rollbackStatus(param);
        //2、回滚中奖者名单
        //是否需要回滚
        if(!winnerNeedRollback(param)){
            //不需要：return
            return;
        }
        //需要回滚
        rollbackWinner(param);
        

    }

    /**
     * 回滚中奖记录：删除奖品下的中奖者
     * @param param
     */
    private void rollbackWinner(DrawPrizeParam param) {
        //使用ActivityStatusManager
        drawPrizeService.deleteRecords(param.getActivityId(), param.getPrizeId());


    }

    private boolean winnerNeedRollback(DrawPrizeParam param) {
        //判断活动中的奖品是否存在中奖者
        int count= winningRecordMapper.countByAPId(param.getActivityId(),param.getPrizeId());
        return count>0;
    }

    /**
     * 恢复相关状态
     * @param param
     */
    private void rollbackStatus(DrawPrizeParam param) {
        ConvertActivityStatusDTO convertActivityStatusDTO = new ConvertActivityStatusDTO();
        convertActivityStatusDTO.setActivityId(param.getActivityId());
        convertActivityStatusDTO.setTargetActivityStatus(ActivityStatusEnum.RUNNING);
        convertActivityStatusDTO.setPrizeId(param.getPrizeId());
        convertActivityStatusDTO.setTargetPrizeStatus(ActivityPrizeStatusEnum.INIT);
        convertActivityStatusDTO.setUserIds(param.getWinnerList().stream()
                .map(DrawPrizeParam.Winner::getUserId).collect(Collectors.toList()));
        convertActivityStatusDTO.setTargetUserStatus(ActivityUserStatusEnum.INIT);
        activityStatusManager.rollbackHandlerEvent(convertActivityStatusDTO);
    }

    private boolean statusNeedRollback(DrawPrizeParam param) {
        //判断活动+奖品+人员表相关状态是否已经发生扭转（正常思路）
        //扭转状态时，保证了事物一致性，要么都扭转了，要么都没扭转（包含活动）
        //因此，只需判断人与或奖品是否扭转过，就能判断状态是否全部扭转
        //不能判断活动已扭转
        //判断奖品是否扭转，就能判断全部状态是否扭转
        ActivityPrizeDO activityPrizeDO = activityPrizeMapper.selectByAPId(param.getActivityId(), param.getPrizeId());
        if (activityPrizeDO.getStatus().equalsIgnoreCase(ActivityStatusEnum.COMPLETED.name())){
            return true;
        }
        return false;
    }

    /**
     * 并发处理抽奖后续流程
     * @param winnerRecordDOList
     */
    private void syncExecute(List<WinningRecordDO> winnerRecordDOList) {
        //短信通知

        //邮件通知
        threadPoolTaskExecutor.execute(()->sendMail(winnerRecordDOList));
    }

    /**
     * 发邮件
     * @param winnerRecordDOList
     */
    private void sendMail(List<WinningRecordDO> winnerRecordDOList) {
        if (CollectionUtils.isEmpty(winnerRecordDOList)){
            log.info("发送中奖列表为空，不用发邮件！");
        }
        for (WinningRecordDO winnerRecordDO : winnerRecordDOList) {
            // 添加null检查，避免NullPointerException
            ActivityPrizeTiersEnum prizeTier = ActivityPrizeTiersEnum.forName(winnerRecordDO.getPrizeTier());
            String prizeTierMessage = "未知奖项"; // 默认值
            if (prizeTier != null) {
                prizeTierMessage = prizeTier.getMessage();
            } else {
                log.warn("无法找到匹配的奖品等级枚举，prizeTiers: {}", winnerRecordDO.getPrizeTier());
            }
            
            String context = "Hi，" + winnerRecordDO.getWinnerName() + "，恭喜你在" + winnerRecordDO.getActivityName() + "活动中获得"
                    + prizeTierMessage +"："
                    + winnerRecordDO.getPrizeName() + "，获奖时间为："
                    + DateUtil.formatTime(winnerRecordDO.getWinningTime()) + "，请尽快领奖！";
            mailUtil.sendSampleMail(winnerRecordDO.getWinnerEmail(),"中奖通知",context);
        }
    }

    /**
     * 状态扭转
     * @param param
     */
    private void statusConvert(DrawPrizeParam param){
        ConvertActivityStatusDTO convertActivityStatusDTO = new ConvertActivityStatusDTO();
        convertActivityStatusDTO.setActivityId(param.getActivityId());
        convertActivityStatusDTO.setTargetActivityStatus(ActivityStatusEnum.COMPLETED);
        convertActivityStatusDTO.setPrizeId(param.getPrizeId());
        convertActivityStatusDTO.setTargetPrizeStatus(ActivityPrizeStatusEnum.COMPLETED);
        convertActivityStatusDTO.setUserIds(
                param.getWinnerList().stream()
                        .map(DrawPrizeParam.Winner::getUserId)
                        .collect(Collectors.toList())
        );
        convertActivityStatusDTO.setTargetUserStatus(ActivityUserStatusEnum.COMPLETED);
        activityStatusManager.handlerEvent(convertActivityStatusDTO);

    }
//    private void statusConvert(DrawPrizeParam param) {
//        //问题：
//        //1、活动状态有依赖性，导致代码维护性差
//        //2、扭转条件可能会拓展
//        //3、代码灵活度低
//        //解决方案：（责任设计模式，策略模式）
//
//        //活动：RUNNING-->COMPLETE  ??全部奖品抽完后才扭转
//        //奖品：INIT-->COMPLETE
//        //人员：INIT-->COMPLETE
//
//        //1、扭转奖品
//        //查询活动关联奖品信息
//        //条件判断是否符合扭转奖品状态： 判断当前状态是否不是COMPLETE，如果不是要扭转
//
//
//        //2、扭转人员
//        //查询活动关联人员信息
//        //条件判断是否符合扭转人员状态： 判断当前状态是否不是COMPLETE，如果不是要扭转
//
//        //3、扭转活动
//        //查询活动信息
//        //条件判断是否符合扭转活动状态： 判断当前状态是否不是COMPLETE，如果不是要扭转
//
//        //更新活动完整信息缓存
//    }

}